package com.common;

import com.alibaba.fastjson2.JSONObject;
import com.common.dto.BucketPolicyConfigDto;
import com.common.dto.MinioUploadDto;
import com.office.common.core.domain.AjaxResult;
import com.office.file.message.domain.FileInfo;
import com.office.file.message.service.IFileInfoService;
import io.minio.*;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import static com.office.common.utils.file.getFileExtensionUtils.getFileExtension;


@RestController
@RequestMapping("/common/minio")
public class CommonMinioController
{
    private static final Logger log = LoggerFactory.getLogger(CommonMinioController.class);
    @Value("${minio.endpoint}")
    private String ENDPOINT;
    @Value("${minio.bucketName}")
    private String BUCKET_NAME;
    @Value("${minio.accessKey}")
    private String ACCESS_KEY;
    @Value("${minio.secretKey}")
    private String SECRET_KEY;

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    @ResponseBody
    public AjaxResult upload(@RequestPart("file") MultipartFile file) {
        try {
            //创建一个MinIO的Java客户端
            MinioClient minioClient = MinioClient.builder()
                    .endpoint(ENDPOINT)
                    .credentials(ACCESS_KEY, SECRET_KEY)
                    .build();
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(BUCKET_NAME).build());
            if (isExist) {
                log.info("存储桶已经存在！");
            } else {
                //创建存储桶并设置只读权限
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(BUCKET_NAME).build());
                BucketPolicyConfigDto bucketPolicyConfigDto = createBucketPolicyConfigDto(BUCKET_NAME);
                SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder()
                        .bucket(BUCKET_NAME)
                        .config(JSONObject.toJSONString(bucketPolicyConfigDto))
                        .build();
                minioClient.setBucketPolicy(setBucketPolicyArgs);
            }
            String filename = file.getOriginalFilename();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            // 设置存储对象名称
            String objectName = sdf.format(new Date()) + UUID.randomUUID() + "." + getFileExtension(filename);
            // 使用putObject上传一个文件到存储桶中
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(BUCKET_NAME)
                    .object(objectName)
                    .contentType(file.getContentType())
                    .stream(file.getInputStream(), file.getSize(), ObjectWriteArgs.MIN_MULTIPART_SIZE).build();
            minioClient.putObject(putObjectArgs);
            log.info("文件上传成功!");
            MinioUploadDto minioUploadDto = new MinioUploadDto();
            minioUploadDto.setName(filename);
            minioUploadDto.setUrl(ENDPOINT + "/" + BUCKET_NAME + "/" + objectName);
            System.out.println(AjaxResult.success(minioUploadDto));
            return AjaxResult.success(minioUploadDto);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("上传发生错误: {}！", e.getMessage());
        }
        return AjaxResult.error();
    }

    /**
     * 创建存储桶的访问策略，设置为只读权限
     */
    private BucketPolicyConfigDto createBucketPolicyConfigDto(String bucketName) {
        BucketPolicyConfigDto.Statement statement = new BucketPolicyConfigDto.Statement();
        statement.setEffect("Allow");
        statement.setPrincipal("*");
        statement.setAction("s3:GetObject");
        statement.setResource("arn:aws:s3:::" + bucketName + "/*.**");
        BucketPolicyConfigDto bucketPolicyConfigDto = new BucketPolicyConfigDto();
        bucketPolicyConfigDto.setVersion("2012-10-17");
        List<BucketPolicyConfigDto.Statement> statements = new ArrayList<>();
        statements.add(statement);
        bucketPolicyConfigDto.setStatement(statements);
        return bucketPolicyConfigDto;
    }

    @RequestMapping(value = "/delete", method = RequestMethod.DELETE)
    @ResponseBody
    public AjaxResult delete(@RequestParam("objectName") String objectName) {
        if (objectName == null || objectName.isEmpty()) {
            return AjaxResult.error("文件名不能为空");
        }
        try {
            MinioClient minioClient = MinioClient.builder()
                    .endpoint(ENDPOINT)
                    .credentials(ACCESS_KEY, SECRET_KEY)
                    .build();
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(BUCKET_NAME).object(objectName).build());
            return AjaxResult.success("删除成功");
        } catch (Exception e) {
            return AjaxResult.error("删除失败：" + e.getMessage());
        }
    }

    /**
     * 下载文件
     *
     * @param fileId
     * @param response
     */
    @Autowired
    private IFileInfoService fileInfoService;

    @GetMapping("/download")
    public void downLoadFile(
            HttpServletResponse response,
            @RequestParam(name = "fileId") @ApiParam(value = "结果ID") Long fileId
    ) throws IOException {
       FileInfo result = fileInfoService.selectFileInfoByFileId(fileId);
        // 文件路径
        String resultValue = result.getCurrentFileUrl();
        // 文件地址的全路径
        String httpUrl =resultValue;
        ServletOutputStream out = null;
        try {
            // 与服务器建立连接
            URL url = new URL(httpUrl);
            URLConnection conn = url.openConnection();
            InputStream inputStream = conn.getInputStream();
            try {
                //1.设置文件ContentType类型，这样设置，会自动判断下载文件类型
                response.setContentType("multipart/octet-stream");
            } catch (Exception e) {
                e.printStackTrace();
            }
            out = response.getOutputStream();
            // 读取文件流
            int len = 0;
            byte[] buffer = new byte[1024 * 10];
            while ((len = inputStream.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

